﻿using Microsoft.Office.Interop.PowerPoint;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using PowerPoint = Microsoft.Office.Interop.PowerPoint;
using Office = Microsoft.Office.Core;
using Drawing = System.Drawing;

namespace ppt_outliner
{
    public partial class SlideTree : UserControl
    {
        private TreeView treeView1;
        private volatile bool isUpdating = false;
        private readonly object updateLock = new object();
        private System.Windows.Forms.Timer refreshTimer;
        private Dictionary<int, WeakReference<Slide>> slideCache;

        public SlideTree()
        {
            InitializeComponent();
            InitializeTreeView();
            InitializeTimer();
            slideCache = new Dictionary<int, WeakReference<Slide>>();
        }

        private void InitializeTimer()
        {
            refreshTimer = new System.Windows.Forms.Timer();
            refreshTimer.Interval = 500; // 500ms
            refreshTimer.Tick += RefreshTimer_Tick;
        }

        private void RefreshTimer_Tick(object sender, EventArgs e)
        {
            try
            {
                if (!isUpdating)
                {
                    RefreshTree();
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"Timer refresh failed: {ex.Message}");
            }
        }

        private void InitializeTreeView()
        {
            treeView1 = new TreeView
            {
                Dock = DockStyle.Fill,
                AllowDrop = true
            };

            treeView1.ItemDrag += treeView1_ItemDrag;
            treeView1.DragEnter += treeView1_DragEnter;
            treeView1.DragDrop += treeView1_DragDrop;
            treeView1.NodeMouseClick += treeView_NodeMouseClick;
            treeView1.BeforeExpand += TreeView_BeforeExpand;
            treeView1.BeforeCollapse += TreeView_BeforeCollapse;

            this.Controls.Add(treeView1);
        }

        public void RefreshTree()
        {
            if (this.InvokeRequired)
            {
                try
                {
                    this.Invoke(new Action(RefreshTree));
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine($"Invoke RefreshTree failed: {ex.Message}");
                }
                return;
            }

            lock (updateLock)
            {
                if (isUpdating) return;
                isUpdating = true;

                try
                {
                    var app = Globals.ThisAddIn.Application;
                    if (app == null || app.Presentations.Count == 0)
                    {
                        ClearTree();
                        return;
                    }

                    var presentation = app.ActivePresentation;
                    if (presentation == null)
                    {
                        ClearTree();
                        return;
                    }

                    UpdateTreeBySlides(presentation);
                }
                catch (COMException ex)
                {
                    System.Diagnostics.Debug.WriteLine($"COM Exception in RefreshTree: {ex.Message}");
                    ClearTree();
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine($"RefreshTree failed: {ex.Message}");
                    ClearTree();
                }
                finally
                {
                    isUpdating = false;
                }
            }
        }

        private void ClearTree()
        {
            if (treeView1.InvokeRequired)
            {
                treeView1.Invoke(new Action(ClearTree));
                return;
            }

            treeView1.Nodes.Clear();
            slideCache.Clear();
        }

        private void UpdateTreeBySlides(Presentation presentation)
        {
            if (presentation == null) return;

            treeView1.BeginUpdate();
            try
            {
                var currentSlides = new Dictionary<int, WeakReference<Slide>>();
                var slideHierarchy = new Dictionary<int, (int slideIndex, int level, int parentIndex)>();

                // 收集幻灯片信息
                foreach (Slide slide in presentation.Slides)
                {
                    try
                    {
                        int slideIndex = slide.SlideIndex;
                        currentSlides[slideIndex] = new WeakReference<Slide>(slide);
                        
                        int level = GetHierarchyLevel(slide);
                        int parentIndex = FindParentSlideIndex(slideIndex, level, slideHierarchy);
                        
                        slideHierarchy[slideIndex] = (slideIndex, level, parentIndex);
                    }
                    catch (Exception ex)
                    {
                        System.Diagnostics.Debug.WriteLine($"Error processing slide: {ex.Message}");
                    }
                }

                // 更新缓存
                slideCache = currentSlides;

                // 重建树
                treeView1.Nodes.Clear();
                BuildTreeFromHierarchy(slideHierarchy);
                treeView1.ExpandAll();
            }
            finally
            {
                treeView1.EndUpdate();
            }
        }

        private int FindParentSlideIndex(int currentIndex, int currentLevel, Dictionary<int, (int slideIndex, int level, int parentIndex)> hierarchy)
        {
            if (currentLevel == 0) return -1;

            for (int i = currentIndex - 1; i >= 1; i--)
            {
                if (hierarchy.ContainsKey(i) && hierarchy[i].level < currentLevel)
                {
                    return i;
                }
            }
            return -1;
        }

        private void BuildTreeFromHierarchy(Dictionary<int, (int slideIndex, int level, int parentIndex)> hierarchy)
        {
            var nodeMap = new Dictionary<int, TreeNode>();

            // 创建所有节点
            foreach (var entry in hierarchy)
            {
                if (slideCache.TryGetValue(entry.Key, out var slideRef) && slideRef.TryGetTarget(out var slide))
                {
                    var node = CreateNode(slide);
                    nodeMap[entry.Key] = node;
                }
            }

            // 构建层级关系
            foreach (var entry in hierarchy)
            {
                if (!nodeMap.ContainsKey(entry.Key)) continue;

                var node = nodeMap[entry.Key];
                var parentIndex = entry.Value.parentIndex;

                if (parentIndex == -1)
                {
                    treeView1.Nodes.Add(node);
                }
                else if (nodeMap.ContainsKey(parentIndex))
                {
                    nodeMap[parentIndex].Nodes.Add(node);
                }
            }
        }

        private TreeNode CreateNode(Slide slide)
        {
            string title = GetSlideTitle(slide);
            return new TreeNode
            {
                Text = title,
                Tag = slide.SlideIndex,
                Name = $"Slide_{slide.SlideIndex}"
            };
        }

        private string GetSlideTitle(Slide slide)
        {
            try
            {
                if (slide.Shapes.HasTitle == Office.MsoTriState.msoTrue)
                {
                    return slide.Shapes.Title.TextFrame.TextRange.Text;
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"Error getting slide title: {ex.Message}");
            }

            return $"Slide {slide.SlideIndex}";
        }

        private int GetHierarchyLevel(Slide slide)
        {
            try
            {
                var box = GetHierarchyBox(slide);
                if (box != null)
                {
                    string levelText = box.TextFrame.TextRange.Text;
                    if (int.TryParse(levelText, out int level))
                    {
                        return level;
                    }
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"Error getting hierarchy level: {ex.Message}");
            }
            return 0;
        }

        private Shape GetHierarchyBox(Slide slide)
        {
            try
            {
                foreach (Shape shape in slide.Shapes)
                {
                    if (shape.Name == "hierarchy_info")
                    {
                        return shape;
                    }
                }
                return CreateHierarchyBox(slide);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"Error getting hierarchy box: {ex.Message}");
                return null;
            }
        }

        private Shape CreateHierarchyBox(Slide slide)
        {
            try
            {
                var box = slide.Shapes.AddTextbox(
                    Office.MsoTextOrientation.msoTextOrientationHorizontal,
                    0, 0, 100, 50);

                box.TextFrame.TextRange.Text = "0";
                box.Name = "hierarchy_info";
                box.Visible = Office.MsoTriState.msoFalse;
                box.TextFrame.TextRange.Font.Size = 12;

                box.Left = (slide.Master.Width - box.Width) / 2;
                box.Top = slide.Master.Height - box.Height;

                return box;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"Error creating hierarchy box: {ex.Message}");
                return null;
            }
        }

        private void treeView1_ItemDrag(object sender, ItemDragEventArgs e)
        {
            if (isUpdating) return;
            treeView1.DoDragDrop(e.Item, DragDropEffects.Move);
        }

        private void treeView1_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = e.AllowedEffect;
        }

        private void treeView1_DragDrop(object sender, DragEventArgs e)
        {
            if (isUpdating) return;

            try
            {
                var pt = treeView1.PointToClient(new Drawing.Point(e.X, e.Y));
                var targetNode = treeView1.GetNodeAt(pt);
                var sourceNode = (TreeNode)e.Data.GetData(typeof(TreeNode));

                if (targetNode == null || targetNode == sourceNode || IsAncestor(sourceNode, targetNode))
                {
                    return;
                }

                MoveNode(sourceNode, targetNode);
                UpdateSlidePositions();
                SavePresentation();
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"Error in drag drop: {ex.Message}");
            }
        }

        private bool IsAncestor(TreeNode potentialAncestor, TreeNode node)
        {
            while (node != null)
            {
                if (node.Parent == potentialAncestor)
                    return true;
                node = node.Parent;
            }
            return false;
        }

        private void MoveNode(TreeNode sourceNode, TreeNode targetNode)
        {
            var newNode = (TreeNode)sourceNode.Clone();
            sourceNode.Remove();

            if (Control.ModifierKeys == Keys.Control)
            {
                var index = targetNode.Index;
                if (targetNode.Parent != null)
                {
                    targetNode.Parent.Nodes.Insert(index + 1, newNode);
                }
                else
                {
                    treeView1.Nodes.Insert(index + 1, newNode);
                }
            }
            else
            {
                targetNode.Nodes.Add(newNode);
            }
        }

        private void UpdateSlidePositions()
        {
            try
            {
                var position = 1;
                foreach (TreeNode node in treeView1.Nodes)
                {
                    UpdateNodePosition(node, ref position, 0);
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"Error updating slide positions: {ex.Message}");
            }
        }

        private void UpdateNodePosition(TreeNode node, ref int position, int level)
        {
            if (node == null) return;

            try
            {
                var slideIndex = (int)node.Tag;
                if (slideCache.TryGetValue(slideIndex, out var slideRef) && slideRef.TryGetTarget(out var slide))
                {
                    slide.MoveTo(position++);

                    var box = GetHierarchyBox(slide);
                    if (box != null)
                    {
                        box.TextFrame.TextRange.Text = level.ToString();
                    }
                }

                foreach (TreeNode child in node.Nodes)
                {
                    UpdateNodePosition(child, ref position, level + 1);
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"Error updating node position: {ex.Message}");
            }
        }

        private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (isUpdating) return;

            try
            {
                var slideIndex = (int)e.Node.Tag;
                if (slideCache.TryGetValue(slideIndex, out var slideRef) && slideRef.TryGetTarget(out var slide))
                {
                    slide.Select();
                }

                HighlightNode(e.Node);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"Error in node click: {ex.Message}");
            }
        }

        private void HighlightNode(TreeNode selectedNode)
        {
            foreach (TreeNode node in treeView1.Nodes)
            {
                ResetNodeColors(node, selectedNode);
            }
        }

        private void ResetNodeColors(TreeNode node, TreeNode selectedNode)
        {
            if (node == selectedNode)
            {
                node.BackColor = Drawing.SystemColors.Highlight;
                node.ForeColor = Drawing.SystemColors.HighlightText;
            }
            else
            {
                node.BackColor = Drawing.SystemColors.Window;
                node.ForeColor = Drawing.SystemColors.WindowText;
            }

            foreach (TreeNode child in node.Nodes)
            {
                ResetNodeColors(child, selectedNode);
            }
        }

        private void SavePresentation()
        {
            try
            {
                var app = Globals.ThisAddIn.Application;
                if (app?.ActivePresentation != null)
                {
                    app.ActivePresentation.Save();
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"Error saving presentation: {ex.Message}");
            }
        }

        private void TreeView_BeforeExpand(object sender, TreeViewCancelEventArgs e)
        {
            treeView1.BeginUpdate();
        }

        private void TreeView_BeforeCollapse(object sender, TreeViewCancelEventArgs e)
        {
            treeView1.BeginUpdate();
        }

        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);
            refreshTimer.Start();
        }
    }
}
